#include <dalelib/graphics/mesh.h>

namespace dalelib
{


void Mesh::loadPLY(const string _Name)
{
	if( _loaded ) { cout << "mesh already loaded" << endl; return; }
	_loaded = true;

	string str;
	ifstream fin( _Name.c_str() );
	if( !fin ) { cout << "cant load mesh file" << endl; return; }

	int num_vertices, num_triangles;

//	int components[11]; // x,y,z,nx,ny,nz,r,g,b,s,t
	int component_order[11];
	memset(component_order,11*sizeof(int),1);
	int num_components = 0;

	while( str.compare("end_header") )
	{
		fin >> str;
		if( !str.compare("element") )
		{
			fin >> str;
			if( !str.compare("vertex") ) fin >> num_vertices;
			if( !str.compare("face") )   fin >> num_triangles;
		}

		if( !str.compare("property") )
		{
			fin >> str; // "float"
			fin >> str; // component name

			if( !str.compare("x") )     component_order[num_components++] =  0;
			if( !str.compare("y") )     component_order[num_components++] =  1;
			if( !str.compare("z") )     component_order[num_components++] =  2;
			if( !str.compare("nx") )    component_order[num_components++] =  3;
			if( !str.compare("ny") )    component_order[num_components++] =  4;
			if( !str.compare("nz") )    component_order[num_components++] =  5;
			if( !str.compare("red") )   component_order[num_components++] =  6;
			if( !str.compare("green") ) component_order[num_components++] =  7;
			if( !str.compare("blue") )  component_order[num_components++] =  8;
			if( !str.compare("s") )     component_order[num_components++] =  9;
			if( !str.compare("t") )     component_order[num_components++] = 10;
		}
	}

	_vertex_array.resize(num_vertices);

	for(int i=0; i<num_vertices; ++i)
	{
		float components[] = { 0,0,0,0,1,0,255,255,255,0,0,}; // defaults
		for(int j=0; j<num_components; ++j)
		{
			fin >> str;
			components[component_order[j]] = atof(str.c_str());
		}

		_vertex_array[i]._pos = v3(components[ 0],components[ 1],components[ 2]);
		_vertex_array[i]._nrm = v3(components[ 3],components[ 4],components[ 5]);
		_vertex_array[i]._col = v3(components[ 6],components[ 7],components[ 8])/255;
		_vertex_array[i]._uv  = v3(components[ 9],components[10],0.f);
	}

	for(int i=0; i<num_triangles; ++i)
	{
		int v[4];
		fin >> str; int num_verts = atoi(str.c_str());
		for(int j=0; j<num_verts; ++j) { fin >> str; v[j] = atoi(str.c_str()); }
		if( num_verts==3 )
		{
			_triangle_array.push_back(Triangle(v[0],v[1],v[2]));
		}
		else if( num_verts==4 )
		{
			_triangle_array.push_back(Triangle(v[0],v[1],v[2]));
			_triangle_array.push_back(Triangle(v[0],v[2],v[3]));
		}
	}
	fin.close();
}

void Mesh::createIndexArray()
{
	int num_indices = _triangle_array.size()*3;
	_index_array.resize(num_indices);
	for(int ii=0,i=0; i<_triangle_array.size(); ++i)
	{
		_index_array[ii++] = _triangle_array[i].v[0];
		_index_array[ii++] = _triangle_array[i].v[1];
		_index_array[ii++] = _triangle_array[i].v[2];
	}

//	calcNormals();
//	dump();

}

void Mesh::calcNormals()
{
	for(int i=0; i<_vertex_array.size(); ++i) _vertex_array[i]._nrm = v3(0,0,0);
	for(int i=0; i<_index_array.size(); i+=3)
	{
		v3 v0 = _vertex_array[_index_array[i+1]]._pos-_vertex_array[_index_array[i]]._pos;
		v3 v1 = _vertex_array[_index_array[i+2]]._pos-_vertex_array[_index_array[i]]._pos;
		v3 nrm = v3::cross(v0,v1).unit();
		_vertex_array[_index_array[i  ]]._nrm += nrm;
		_vertex_array[_index_array[i+1]]._nrm += nrm;
		_vertex_array[_index_array[i+2]]._nrm += nrm;
	}
	for(int i=0; i<_vertex_array.size(); ++i) _vertex_array[i]._nrm.normalise();
}

void Mesh::invertNormals()
{
	for(int i=0; i<_vertex_array.size(); ++i) _vertex_array[i]._nrm *= -1.f;
//	calcNormals();
}

void Mesh::transform(const m4 _Transform)
{
    m4 mvit = _Transform.inverse().transpose();
	for(int i=0; i<_vertex_array.size(); ++i)
	{
        _vertex_array[i]._pos = _Transform.transformPoint(_vertex_array[i]._pos);
        _vertex_array[i]._nrm = mvit.transformVector(_vertex_array[i]._nrm);
    }
}

void Mesh::draw()
{
	if( _index_array.empty() ) createIndexArray();

	glEnableClientState( GL_VERTEX_ARRAY );
	glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), &_vertex_array[0]._pos );

	glEnableClientState( GL_NORMAL_ARRAY );
	glNormalPointer( GL_FLOAT, sizeof(Vertex), &_vertex_array[0]._nrm );

	glEnableClientState( GL_COLOR_ARRAY );
	glColorPointer( 3, GL_FLOAT, sizeof(Vertex), &_vertex_array[0]._col );

	glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	glTexCoordPointer( 3, GL_FLOAT, sizeof(Vertex), &_vertex_array[0]._uv );

	glDrawElements( GL_TRIANGLES, _index_array.size(), GL_UNSIGNED_INT, (GLvoid*)&_index_array[0] );

	glDisableClientState( GL_VERTEX_ARRAY );
	glDisableClientState( GL_NORMAL_ARRAY );
	glDisableClientState( GL_COLOR_ARRAY );
	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}

void Mesh::dump()
{

	for(int i=0; i<_vertex_array.size(); ++i)
	{
		cout << "vertices " << i << ": " << endl;
		cout << "   pos: " << _vertex_array[i]._pos[0] << ", "  << _vertex_array[i]._pos[1] << ", "  << _vertex_array[i]._pos[2] << endl;
		cout << "   nrm: " << _vertex_array[i]._nrm[0] << ", "  << _vertex_array[i]._nrm[1] << ", "  << _vertex_array[i]._nrm[2] << endl;
		cout << "   col: " << _vertex_array[i]._col[0] << ", "  << _vertex_array[i]._col[1] << ", "  << _vertex_array[i]._col[2] << endl;
		cout << "   uv:  " << _vertex_array[i]._uv[ 0] << ",  " << _vertex_array[i]._uv[ 1] << endl;
	}

	for(int i=0; i<_index_array.size(); i+=3)
	{
		cout << "triangle " << i/3 << ": " << _index_array[i] << ", " << _index_array[i+1] << ", " << _index_array[i+2] << endl;
	}

}



} // namespace dalelib
